﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SPMS.Utility;
using SPMS.Log.Utility;

namespace SPMS.Log
{
    /// <summary>
    /// 日志级别映射表
    /// </summary>
    /// <remarks>用于将日志级别名称与日志级别进行映射</remarks>
    /// <history>
    /// [zanezeng]               2009/10/16 15:25    创建
    /// </history>
    public sealed class LevelMap
    {
        #region ---Constructor

        /// <summary>
        /// 初始化类型<see cref="LevelMap"/>的新实例
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/16 16:33    创建
        /// </history>
        public LevelMap()
            : this( null, false )
        {
        }

        /// <summary>
        /// 初始化类型<see cref="LevelMap"/>的新实例
        /// </summary>
        /// <param name="includeBuildinLevels">是否包含内置日志级别</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/16 16:34    创建
        /// </history>
        public LevelMap( bool includeBuildinLevels )
            : this( null, includeBuildinLevels )
        {
        }

        /// <summary>
        /// 初始化类型<see cref="LevelMap"/>的新实例
        /// </summary>
        /// <param name="parent">当前日志级别映射表的上一级日志级别映射表</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/7 17:38    创建
        /// </history>
        public LevelMap( LevelMap parent )
            : this( parent, false )
        {

        }

        /// <summary>
        /// 初始化类型<see cref="LevelMap"/>的新实例
        /// </summary>
        /// <param name="parent">当前日志级别映射表的上一级日志级别映射表</param>
        /// <param name="includeBuildinLevels">是否包含内置日志级别</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/7 17:38    创建
        /// </history>
        public LevelMap( LevelMap parent, bool includeBuildinLevels )
        {
            //判断是否包含内置日志级别
            if (includeBuildinLevels)
            {
                //循环添加内置数据
                foreach (Level buildinLevel in BuildinLevels)
                {
                    //添加内置级别
                    this.LevelDictionary.Add( buildinLevel.Name, buildinLevel );
                }
            }

            //保存参数
            this.m_Parent = parent;
        }

        /// <summary>
        /// 初始化类型<see cref="LevelMap"/>
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/16 16:34    创建
        /// </history>
        static LevelMap()
        {
            //创建内置日志级别映射表
            s_BuildinLevels = new Dictionary<string, Level>();

            //注册内置日志级别
            RegisterBuildinLevel( Level.Alert );
            RegisterBuildinLevel( Level.All );
            RegisterBuildinLevel( Level.Critical );
            RegisterBuildinLevel( Level.Debug );
            RegisterBuildinLevel( Level.Emergency );
            RegisterBuildinLevel( Level.Error );
            RegisterBuildinLevel( Level.Fatal );
            RegisterBuildinLevel( Level.Fine );
            RegisterBuildinLevel( Level.Info );
            RegisterBuildinLevel( Level.Notice );
            RegisterBuildinLevel( Level.Off );
            RegisterBuildinLevel( Level.Severe );
            RegisterBuildinLevel( Level.Trace );
            RegisterBuildinLevel( Level.Verbose );
            RegisterBuildinLevel( Level.Warn );
        }

        #endregion

        #region ---Public Method

        /// <summary>
        /// 将给定的日志级别注册到日志级别映射中
        /// </summary>
        /// <param name="level">要注册的日志级别</param>
        /// <remarks></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="level"/>为Null</exception>
        /// <history>
        /// [zanezeng]               2009/10/16 15:32    创建
        /// </history>
        public void RegisterLevel( Level level )
        {
            //断言参数
            ArgumentAssert.AssertArgumentNotNull( level, "level" );

            //缓存日志级别
            this.LevelDictionary[level.Name] = level;
        }

        /// <summary>
        /// 注册日志级别
        /// </summary>
        /// <param name="name">要注册的日志级别的名称</param>
        /// <param name="value">要注册日志级别的值</param>
        /// <remarks></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="name"/>为<c>Null</c>或者为空字符串</exception>
        /// <history>
        /// [zanezeng]               2009/10/16 15:32    创建
        /// </history>
        public void RegisterLevel( string name, int value )
        {
            //转调
            this.RegisterLevel( name, value, name );
        }

        /// <summary>
        /// 将给定的日志级别注册到日志级别映射中
        /// </summary>
        /// <param name="name">要注册的日志级别的名称</param>
        /// <param name="value">要注册日志级别的值</param>
        /// <param name="displayName">要注册日志级别的显示名称</param>
        /// <remarks></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="name"/>为<c>Null</c>或者为空字符串</exception>
        /// <history>
        /// [zanezeng]               2009/10/16 15:32    创建
        /// </history>
        public void RegisterLevel( string name, int value, string displayName )
        {
            //断言参数
            ArgumentAssert.AssertStringArgumentNotNullOrEmpty( name, "name" );

            //创建日志级别
            Level level = new Level( name, value, displayName );

            //注册日志级别
            this.RegisterLevel( level );
        }

        /// <summary>
        /// 检索给定名称的日志级别
        /// </summary>
        /// <param name="name">要检索的日志级别的名称</param>
        /// <param name="defaultValue">默认的日志级别</param>
        /// <returns>给定名称的日志级别，当给定名称的日志级别不存在时返回给定的默认日志级别</returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/16 15:50    创建
        /// </history>
        public Level LookupLevelWithDefault( string name, Level defaultValue )
        {
            //获得日志级别
            Level existedLevel = this[name];

            //返回日志级别
            return (null == existedLevel) ? defaultValue : existedLevel;
        }

        /// <summary>
        /// 检索给定日志级别值的日志级别
        /// </summary>
        /// <param name="value">要检索的日志级别的值</param>
        /// <param name="defaultValue">默认的日志级别</param>
        /// <returns>给定值的日志级别，当给定值的日志级别不存在时返回给定的默认日志级别</returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/8 10:51    创建
        /// </history>
        public Level LookupLevelWithDefault( int value, Level defaultValue )
        {
            //获得日志级别
            Level existedLevel = this[value];

            //返回日志级别
            return (null == existedLevel) ? defaultValue : existedLevel;
        }

        #endregion

        #region ---Proeprty

        /// <summary>
        /// 获得给定日志级别名称对应的日志级别
        /// </summary>
        /// <value>给定日志级别名称对应的日志级别</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/16 15:45    创建
        /// </history>
        public Level this[string name]
        {
            get
            {
                //用于保存日志级别
                Level existedLevel = null;

                //判断日志级别名称是否为NULL
                if (!string.IsNullOrEmpty( name ))
                {
                    //尝试获得日志级别
                    if (null != this.m_Levels && this.m_Levels.TryGetValue( name, out existedLevel ))
                    {
                        //如果日志级别存在，则返回当前日志映射表中的日志级别
                        return existedLevel;
                    }
                    //如果日志级别不存在，则尝试返回上一级日志级别映射表的日志级别
                    else if (null != this.m_Parent)
                    {
                        //返回上一级日志级别映射表的日志级别
                        return this.m_Parent[name];
                    }
                    else
                    {
                        //尝试获得内置日志级别
                        s_BuildinLevels.TryGetValue( name, out existedLevel );
                    }
                }

                //返回日志级别
                return existedLevel;
            }
        }

        /// <summary>
        /// 获得给定日志级别值对应的日志级别
        /// </summary>
        /// <value>指定索引处的元素</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/8 10:53    创建
        /// </history>
        public Level this[int value]
        {
            get
            {
                //尝试获得日志级别
                if (null != this.m_Levels)
                {
                    //循环检索
                    foreach (Level sourceLevel in this.m_Levels.Values)
                    {
                        //判断日志级别值是否相等
                        if (value == sourceLevel.Value)
                        {
                            //如果相等，则返回日志级别
                            return sourceLevel;
                        }
                    }
                }

                //如果日志级别不存在，则尝试返回上一级日志级别映射表的日志级别
                if (null != this.m_Parent)
                {
                    //返回上一级日志级别映射表的日志级别
                    return this.m_Parent[value];
                }

                //循环检索
                foreach (Level sourceLevel in s_BuildinLevels.Values)
                {
                    //判断日志级别值是否相等
                    if (value == sourceLevel.Value)
                    {
                        //如果相等，则返回日志级别
                        return sourceLevel;
                    }
                }

                //如果不存在，则返回空引用
                return null;
            }
        }

        /// <summary>
        /// 获得已经注册的所有日志级别
        /// </summary>
        /// <value>已经注册的所有日志级别</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/16 15:50    创建
        /// </history>
        public Level[] Levels
        {
            get
            {
                return this.LevelDictionary.Values.ToArray();
            }
        }

        /// <summary>
        /// 获得内置日志级别
        /// </summary>
        /// <value>内置日志级别</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/16 16:39    创建
        /// </history>
        public static Level[] BuildinLevels
        {
            get
            {
                return s_BuildinLevels.Values.ToArray();
            }
        }

        /// <summary>
        /// 获得日志级别字典
        /// </summary>
        /// <value>日志级别字典</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/7 17:41    创建
        /// </history>
        private SynchronizedDictionary<string, Level> LevelDictionary
        {
            get
            {
                //判断日志级别缓存是否创建
                if (null != this.m_Levels)
                {
                    //如果已经创建，则直接返回
                    return this.m_Levels;
                }

                //同步
                lock (this)
                {
                    //判断日志级别缓存是否创建
                    if (null != this.m_Levels)
                    {
                        //如果已经创建，则直接返回
                        return this.m_Levels;
                    }

                    //创建日志级别缓存
                    this.m_Levels = new SynchronizedDictionary<string, Level>();
                }

                //返回日志级别缓存
                return this.m_Levels;
            }
        }

        #endregion

        #region ---Private Method

        /// <summary>
        /// 注册内置日志级别
        /// </summary>
        /// <param name="level">要注册的内置日志级别</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/16 16:36    创建
        /// </history>
        private static void RegisterBuildinLevel( Level level )
        {
            s_BuildinLevels.Add( level.Name, level );
        }

        #endregion

        #region ---Field

        /// <summary>
        /// 日志级别缓存
        /// </summary>
        private SynchronizedDictionary<string, Level> m_Levels;

        /// <summary>
        /// 上级日志级别映射表
        /// </summary>
        private LevelMap m_Parent;

        /// <summary>
        /// 内置日志级别
        /// </summary>
        private readonly static Dictionary<string, Level> s_BuildinLevels;

        #endregion
    }
}
